Add support async scripts - #50
Conversation
|
I'll finish the review on Monday. |
|
@raymondfeng what is your scenario where you need to control the order in which the boot scripts are invoked and where the script name is not good enough? The same thing you are trying to achieve in this PR can be achieved to a certain degree by prepending a number to the script name, e.g. One of the reasons why I am against the idea of using numbers for ordering boot scripts, is that external modules (yeoman generators, loopback components) need to specify the ordering in relative means (run this after that) instead of using an absolute position (run this as the script no. 3). This is not a new problem, we have to solve it for middleware ordering too - see #44. The second reason is more practical: when the order is defined by both file names and optional BTW this is the reason why I asked you to split this patch into two PRs. While I did not review the async boot scripts in detail, it seems rather uncontroversial, thus I expect it can be reviewed and merged quickly. |
|
The ordering part of the PR was driven by a use case to discover models programmatically from a database during the boot process and expose the discovered models as REST APIs. The code needs to be executed before the API explorer/REST middleware is loaded. I'm fine to refine the mechanism of ordering, for example, we can have boot.json or file name patterns. It's a bit tricky to split the PRs. I don't know how to create a PR on top of another PR as the tests also use the async booting. |
|
Let's keep this PR focused on boot script ordering (perhaps change the title) then. Can you submit |
1081264 to
f9a5654
Compare
|
OK, I reverted the changes for ordering and leave this PR for async booting. |
There was a problem hiding this comment.
I remember I was already commenting on this one in the original all-in-one commit you send me to look at. Can you find it please?
f9a5654 to
869ff61
Compare
|
I believe that I have addressed your comments with the last push. Please verify. Now with the behavior of s1.js: module.exports = function(app) {
...
}s2.js module.exports = function(app, callback) {
...
}If no callback is provided by boot(), s1 and s2 are executed synchronously and the callback is no-op for s2. When callback is provided by boot(), s1 is executed synchronously and s2 is executed asynchronously but they are still in series. |
There was a problem hiding this comment.
If one of these asserts fails, the error message will be very unhelpful.
Solution A:
expect(process.bootFlags.fooLoaded, 'fooLoaded').to.equal(true);
// etc.Solution B:
expect(process.bootFlags).to.eql({
fooLoaded: true,
barLoaded: true,
// barProcessed is not set, will be set in the next tick
barSyncLoaded: true
});The latter provides most context, as the assert library has all four properties available to print them in the error message.
|
The algorithm looks good now. It is much simpler that the initial version, which is almost always a good sing. I left a bunch of comments on the coding style. |
|
On the second thought, the tests need more changes. At the moment, they check only the fact that the scripts were executed, but they don't verify the order of execution. Here is a proposed solution. Note how the unit tests nicely describe how the boot process works. Edit: I fixed the tests to reflect the fact that all scripts are required first and only then the exported functions are called. // boot/bar.js
process.bootFlags.push('barLoaded');
module.exports = function(app, callback) {
process.bootFlags.push('barStarted');
process.nextTick(function() {
process.bootFlags.push('barFinished');
callback();
});
};
// boot/barSync.js
process.bootFlags.push('barSyncLoaded');
module.exports = function(app) {
process.bootFlags.push('barSyncExecuted');
});
// boot/foo.js
process.bootFlags.push('fooLoaded');
// test - boot with callback
expect(process.bootFlags).to.eql([
'barLoaded',
'barSyncLoaded',
'fooLoaded'
'barStarted',
'barFinished',
'barSyncExecuted',
]);
// test - boot without callback
expect(process.bootFlags).to.eql([
'barLoaded',
'barSyncLoaded',
'fooLoaded'
'barStarted'
// everything else happens in the next tick and later
]);
setTimeout(function() {
// all async boot scripts are done by this time
expect(process.bootFlags).to.eql([
'barLoaded',
'barSyncLoaded',
'fooLoaded'
'barStarted',
'barFinished',
'barSyncExecuted',
]);
}, 10); |
|
Now that the order of execution is nicely visible in the comment above, I see that this patch is introducing a backwards-incompatible change. When @raymondfeng Is that the reason why you had different paths for I am wondering what is the likelihood that somebody is doing stuff outside the exported function that depends on changes made by a previous boot script in its exported function. It seems very unlikely to me, thus I think we can get away with making the change. |
|
One more thing @raymondfeng - please add My vision is that with DEBUG turned on, the user should be able to see an output similar to the expected array in the test outlined by my comment above, so that he can reason about the order in which his code was executed. |
df8129a to
d179846
Compare
|
DEBUG statements added. |
There was a problem hiding this comment.
This file is not needed by the test, please remove it.
|
@raymondfeng I am not happy with the way how you are working around the I am not against having sync and async fixture per se, but we should fix the real problem too. Also note that the current tests do not test sync call of Here is the solution for The proper solution is very easy:
|
d179846 to
f89c943
Compare
|
Issues addressed. |
There was a problem hiding this comment.
Since there is no async app anymore, it would be better to get rid of simpleAsyncAppInstructions altogether. It's not a big deal, I can live with the current code too.
f89c943 to
94cb4d6
Compare
/to @bajtos
/cc @ritch
The PR adds two enhancements for boot:
Allow boot scripts to be executed asynchronously